class symbolTableObject:
    def __init__(self, value, type, addr=None):
        self.value = value
        self.type  = type

        if addr == None :
            self.addr = None
        else :
            self.addr = addr
            

class SymbolTable:

    __hasParentSymTable = False

    def __init__(self) :
	self.__nameTable = {}
        self.__FP        = 0
        self.__FPB       = 0
        self.__SP        = 0
        self.__scratch   = 0

	self.__tempVarIndex  = 0
	self.__numParams	= 0
        self.__numConsts     = 0
        self.__numVars       = 0
        self.__numTemps      = 0

    def setParentTable(self, parentTable):
	self.__hasParentSymTable = True
	self.__parentTable = parentTable

    def newTempVarName(self):
        self.__tempVarIndex += 1
        return "T"+str(self.__tempVarIndex)

    def newTempVar(self):
        '''new and add a temp variable in the symbol table
           return variable symber'''
        self.__numTemps += 1
        ret = symbolTableObject(0, "temp")
        tTempVar = self.newTempVarName() 
        self.__nameTable[tTempVar] = ret
        return tTempVar
            
    def newConstVar(self, nConst):
        '''new and add a const variable to the symbol table
           return variable symber'''        
        ret = symbolTableObject(nConst, "const")
        NUMBER = str(nConst)
        if not self.__nameTable.__contains__(NUMBER) :
            self.__numConsts +=1
            self.__nameTable[NUMBER] = ret
            # add constant to all symbol tables
            if self.__hasParentSymTable == True:
                self.__parentTable.newConstVar(nConst)

        return NUMBER 

        #def newVarVar(self, varName):
	#	'''new and add a variable variable to the symbol table
	#	   return variable symber'''
        #       self.__numVars += 1
	#	ret = symbolTableObject(0, "var")
	#	self.__nameTable[varName] = ret
	#	return varName

    def newVarVar(self, varName):
        '''new and add a variable variable to the symbol table
           return variable symber'''
        if varName == "return" :
            return self.newReturnVar(varName)
        else :
            self.__numVars += 1
            ret = symbolTableObject(0, "var")
            self.__nameTable[varName] = ret
            return varName

    #added field for parameters
    def newParamVar(self, paramName):
        '''new and add a parameter to the symbol table
           return parameter symbol'''
        self.__numParams += 1
        ret = symbolTableObject(0, "param")
        self.__nameTable[paramName] = ret
        return paramName
    #end of parameters functions

    #for the return variable
    def newReturnVar(self, name):
        ret = symbolTableObject(0, "ret")
        self.__nameTable[name] = ret
        return name

    def getFrameLength(self):
        '''return the length of the activation record
           return value, prev fp and ret. addr count 3'''
        l = self.__numParams + self.__numVars + self.__numTemps
        if "return" not in self.__nameTable:
            l += 3
        else:
            l += 2
        return l

    #function to get activation for a function/ 
    #this will be similar to the mem file
    def updateForActivationRecord(self):
        paramStartAddr = 0
        varsStartAddr  = self.__numParams + paramStartAddr
        tempsStartAddr = varsStartAddr + self.__numVars 
        returnValueAddr = tempsStartAddr + self.__numTemps 
        activationRecord = {}
        for item in self.__nameTable :
            symbolItem = self.__nameTable[item]
            if symbolItem.type == "temp" :
                symbolItem.addr = tempsStartAddr
                tempsStartAddr += 1
            elif symbolItem.type == "var" :
                symbolItem.addr = varsStartAddr
                varsStartAddr += 1
            elif symbolItem.type == "ret" :
                symbolItem.addr = returnValueAddr
            elif symbolItem.type == "param" :
                symbolItem.addr = paramStartAddr
                paramStartAddr += 1
            else :
                'SymbolItem is a label do nothing'

            if symbolItem.addr != None :
                activationRecord[symbolItem.addr] = str(symbolItem.value) + "\t; " + symbolItem.type + " " + item	
            if self.__nameTable["return"]:
                pass
            else:
                ret = symbolTableObject(0,"ret")
                ret.addr = returnValueAddr
                activationRecord[ret.addr] = str(ret.value) + "\t; " + ret.type + " " + "return"	
			
        returnAddr = symbolTableObject(0,"var")	#symbolTableObject(0, "var")
        returnAddr.addr = returnValueAddr + 2
        self.__nameTable["returnAddr"] = returnAddr
        activationRecord[returnAddr.addr] = str(returnAddr.value) + "\t; " + returnAddr.type + " " + "returnAddr"
        prevFP = symbolTableObject(0,"var")
        prevFP.addr = returnValueAddr + 1
        self.__nameTable["prevFP"] = prevFP
        activationRecord[prevFP.addr] = str(prevFP.value) + "\t; " + prevFP.type + " " + "prevFP"
	
        #print str(activationRecord)
        return activationRecord	

    #end of method

    def assignAddresses(self) :

        constStartAddr = 5
        varsStartAddr  = self.__numConsts + constStartAddr
        tempsStartAddr = varsStartAddr + self.__numVars

        'Set the addresses then print to memory file'
        memFileMap = {}
            
        for item in self.__nameTable :
            symbolItem = self.__nameTable[item]
            if symbolItem.type == "temp" :
                symbolItem.addr = tempsStartAddr
                tempsStartAddr += 1
                print "temp addr: " + str(tempsStartAddr)
            elif symbolItem.type == "var" :
                symbolItem.addr = varsStartAddr
                varsStartAddr += 1
            elif symbolItem.type == "const" :
                symbolItem.addr = constStartAddr
                constStartAddr += 1
            else :
                'SymbolItem is a label do nothing'
                print "ERROR"
                print symbolItem.name

            if symbolItem.addr != None :
                memFileMap[symbolItem.addr] = str(symbolItem.value) + "\t; " + symbolItem.type + " " + item
            else :
                print "NONE FOUND"

        self.__SP = tempsStartAddr - 1
        print "SP: " + str(self.__SP)
        memfile = open("prog.mem", 'w')

        memfile.write("1" + "\t" + str(self.__SP) + "\t; SP\n")
        memfile.write("2" + "\t" + str(self.__FP) + "\t; FP\n")
        memfile.write("3" + "\t" + str(self.__FPB) + "\t; FPB\n")
        memfile.write("4" + "\t" + str(self.__scratch) + "\t; scratch\n")
        for i in memFileMap :
            mapping = str(i) + "\t" + memFileMap[i] + "\n"
            memfile.write(mapping)              

        memfile.close()

    def printSymbolTable(self):
        for item in self. __nameTable :
            symbolItem = self.__nameTable[item]
            print "Name = %s Value = %s Type = %s Addr = %s" % (str(item), str(symbolItem.value), str(symbolItem.type), str(symbolItem.addr))
	
    def debugMsg(self):
        print "#Vars = %d #Temp = %d #Const = %d" % (self.__numVars, self.__numTemps, self.__numConsts)
        print "len of the activation record = %d" % (self.getActivationRecordLen())

    def __getattr__(self, key):
        if self.__nameTable.__contains__(key) :
            return self.__nameTable[key]
        else :
            return None

    def __contains__(self, value):
        return value in self.__nameTable
